#include "Guardian.h"

#include "GuardianFall.h"
#include "GuardianIdle.h"
#include "GuardianJump.h"
#include "GuardianWalk.h"

//====================================================================================================
// Class Definitions
//====================================================================================================

Guardian::Guardian()
	: mpCurrentState(NULL)
	, mPosition(0.0f, 0.0f)
	, mVelocity(0.0f, 0.0f)
	, mFacingLeft(false)
{
	memset(mGuardianStates, 0, sizeof(GuardianState*) * AS_Max);
}

//----------------------------------------------------------------------------------------------------

Guardian::~Guardian()
{
	// Empty
}

//----------------------------------------------------------------------------------------------------

void Guardian::Load()
{
	// Clear everything
	Unload();

	// Create character states
	mGuardianStates[AS_Idle] = new GuardianIdle(this);
	mGuardianStates[AS_Walk] = new GuardianWalk(this);
	mGuardianStates[AS_Jump] = new GuardianJump(this);
	mGuardianStates[AS_Fall] = new GuardianFall(this);

	// Load state resources
	for (int i = 0; i < AS_Max; ++i)
		mGuardianStates[i]->Load();

	// Set default state
	ChangeState(AS_Fall);
}

//----------------------------------------------------------------------------------------------------

void Guardian::Unload()
{
	for (int i = 0; i < AS_Max; ++i)
	{
		if (mGuardianStates[i] != NULL)
		{
			mGuardianStates[i]->Unload();
			delete mGuardianStates[i];
			mGuardianStates[i] = NULL;
		}
	}
	mpCurrentState = NULL;
}

//----------------------------------------------------------------------------------------------------

void Guardian::Update(float deltaTime, const Map& map)
{
	// Update the current state
	mpCurrentState->Update(deltaTime);

	// Apply gravity
	mVelocity.y += (int)(100.0f * deltaTime);
	mVelocity.y = Min(32.0f, mVelocity.y);

	// Apply movement
	CheckCollision(deltaTime, map);
}

//----------------------------------------------------------------------------------------------------

void Guardian::Render(const SVector2& offset)
{
	mpCurrentState->Render(offset);
}

//----------------------------------------------------------------------------------------------------

void Guardian::ChangeState(AnimationState as)
{
	// Check if we are already in this state
	if (mpCurrentState == mGuardianStates[as])
		return;

	// Exit the current state
	if (mpCurrentState != NULL)
		mpCurrentState->Exit();

	// Switch to the new state
	mpCurrentState = mGuardianStates[as];

	// Enter the new state
	if (mpCurrentState != NULL)
		mpCurrentState->Enter();
}

//----------------------------------------------------------------------------------------------------

const char* Guardian::GetCurrentState()
{
	const char* name = "Unknown";
	if (mpCurrentState != NULL)
	{
		name = mpCurrentState->GetName();
	}
	return name;
}

//----------------------------------------------------------------------------------------------------

SRect Guardian::GetBoundingBox() const
{
	return mpCurrentState->GetBoundingBox();
}

//----------------------------------------------------------------------------------------------------

void Guardian::CheckCollision(float deltaTime, const Map& map)
{
	// Check collision
	SRect bb = GetBoundingBox();
	SRect newbb = bb + SVector2(mVelocity.x, 0.0f);
	SRect rightbb = map.GetBoundingBoxFromSegment(newbb.GetRightSegment());
	SRect leftbb = map.GetBoundingBoxFromSegment(newbb.GetLeftSegment());

	// Right collision
	if (mVelocity.x > 0.0f && rightbb.IsValid())
	{
		mPosition.x += static_cast<int>(rightbb.min.x - bb.max.x) - 1.0f;
	}
	// Left collision
	else if (mVelocity.x < 0.0f && leftbb.IsValid())
	{
		mPosition.x += static_cast<int>(leftbb.max.x - bb.min.x) + 1.0f;
	}
	else
	{
		mPosition.x += static_cast<int>(mVelocity.x);
	}

	// Check collision
	newbb = bb + SVector2(0.0f, mVelocity.y);
	SRect bottombb = map.GetBoundingBoxFromSegment(newbb.GetBottomSegment());
	SRect topbb = map.GetBoundingBoxFromSegment(newbb.GetTopSegment());

	// Bottom collision
	if (mVelocity.y > 0.0f && bottombb.IsValid())
	{
		mPosition.y += static_cast<int>(bottombb.min.y - bb.max.y) - 1.0f;
		mVelocity.y = 0.0f;
		if (mpCurrentState == mGuardianStates[AS_Fall])
		{
			ChangeState(AS_Idle);
		}
	}
	// Top collision
	else if (mVelocity.y < 0.0f && topbb.IsValid())
	{
		mPosition.y += static_cast<int>(topbb.max.y - bb.min.y) + 1.0f;
		mVelocity.y = 0.0f;
	}
	else
	{
		mPosition.y += static_cast<int>(mVelocity.y);
		if (mpCurrentState == mGuardianStates[AS_Idle] ||
			mpCurrentState == mGuardianStates[AS_Walk])
		{
			ChangeState(AS_Fall);
		}
	}
}



//void Guardian::Render(const SVector2& viewOffset)
//{
//	int width = mSprite.GetWidth();
//	int height = mSprite.GetHeight();
//	SVector2 offset(width * 0.5f, height * 0.5f);
//	SVector2 renderPosition = mPosition - offset - viewOffset; 
//	mSprite.SetPosition(renderPosition);
//	mSprite.Render();
//};

//SRect Guardian::GetBoundingBox() const
//{
//	SRect boundingBox;
//	boundingBox.min.x = mPosition.x - 16.0f;
//	boundingBox.max.x = mPosition.x + 16.0f;
//	boundingBox.min.y = mPosition.y - 30.0f;
//	boundingBox.max.y = mPosition.y + 30.0f;
//	return boundingBox;
//}